package com.sihai.core.support;

import org.apache.commons.lang.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <code>HqlSyntaxAnalyzer</code> Hibernate HQL语法分析器
 */
public class HqlSyntaxAnalyzer {

    /**
     * from关键字的正则表达式模式
     */
    private static final String FROM_PATTERN = "(?i)from";

    /**
     * order关键字的正则表达式模式
     */
    private static final String ORDER_PATTERN = "(?i)order";


    private Pattern fromPattern;

    private Pattern orderPattern;

    private String hql;

    /**
     * @param hql Hibernate query language.
     */
    public HqlSyntaxAnalyzer(String hql) {
        this.hql = StringUtils.trimToEmpty(hql);
        fromPattern = Pattern.compile(FROM_PATTERN);
        orderPattern = Pattern.compile(ORDER_PATTERN);
    }


    /**
     * @return 是否update(delete)操作
     */
    public boolean isUpdateSentence() {
        return StringUtils.startsWithIgnoreCase(hql, "update") || StringUtils.startsWithIgnoreCase(hql, "delete");
    }


    /**
     * @return 主语句的from所在的位置索引
     */
    public int getPrimaryFromIndex() {
        Matcher matcher = fromPattern.matcher(hql);
        while (matcher.find()) {
            int index = matcher.start();
            if (!isEnclosedByParenthesis(index, matcher.group())) {
                return index;
            }
        }
        throw new IllegalArgumentException("illegl hql:" + this.hql);
    }


    /**
     * @return 主语句order所在位置的索引
     */
    public int getPrimaryOrderbyIndex() {
        Matcher matcher = orderPattern.matcher(hql);
        int index = -1;
        while (matcher.find()) {
            index = matcher.start();
        }
        return index;
    }

    /**
     * 是否正好被()包围
     *
     * @param begin begin index
     * @param value search value
     * @return isEnclosed by specific value
     */
    protected boolean isEnclosedByParenthesis(int begin, String value) {
        boolean[] result = new boolean[2];
        int index = begin;
        while (index >= 0) {
            char current = this.hql.charAt(index);
            if (current == ')') {
                return false;
            }
            if (current == '(') {
                result[0] = true;
                break;
            }
            index--;
        }

        index = begin + value.length();
        while (index <= this.hql.length() - 1) {
            char current = this.hql.charAt(index);
            if (current == '(') {
                return false;
            }
            if (current == ')') {
                result[1] = true;
                break;
            }
            index++;
        }
        return result[0] && result[1];
    }
}
